package cn.langpy.simforkjoin.core;

import cn.langpy.simforkjoin.annotation.ForkJoin;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.*;
import java.util.logging.Logger;

@Component
public class ContextTask {
    public static Logger log = Logger.getLogger(ContextTask.class.toString());

    @Autowired
    ApplicationContext applicationContext;
    @Resource(name = "defaultExecutor")
    ExecutorService defaultExecutor;

    public int execute(CompletionService executor, ProceedingJoinPoint joinPoint, Object[] args, int threshold) {
        List arg = (List) args[0];
        int len = arg.size();
        int n = len / threshold;
        log.info("sim-forkjoin=>data size: "+len+",and the data will be divide into "+n+" threads.");
        for (int i = 0; i < n; i++) {
            int start = threshold * i;
            int end = i == n - 1 ? len : start + threshold;
            executor.submit(new CutTask(joinPoint, args, start, end));
        }
        return n;
    }

    public boolean validate(ForkJoin forkJoin, Object[] args) {
        if (args == null || args.length == 0) {
            throw new RuntimeException("the method with @ForkJoin needs a non-null parameter,and the method's first parameter type must be List.");
        }
        if (!(args[0] instanceof List)) {
            throw new RuntimeException("the first parameter type of the method with @ForkJoin musts be List.");
        }
        if (forkJoin.threshold() <= 0) {
            throw new RuntimeException("@ForkJoin's threshold musts be greater than 0.");

        }
        return true;
    }

    public Executor getExecutor(ForkJoin forkJoin) {
        ExecutorService asyncTaskExecutor = null;
        if (forkJoin.executor() != null && forkJoin.executor().length() > 0) {
            Object e = applicationContext.getBean(forkJoin.executor());
            return (Executor) e;
        }else{
            asyncTaskExecutor = defaultExecutor;
        }
        return asyncTaskExecutor;
    }

}
